package com.yuzhi.master.drainStPptnr.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuzhi.common.contant.Constants;
import com.yuzhi.common.core.domain.PageQuery;
import com.yuzhi.common.core.page.PageDataInfo;
import com.yuzhi.common.exception.base.BaseException;
import com.yuzhi.master.drainCorrelation.domain.vo.DrainCorrelationVo;
import com.yuzhi.master.drainCorrelation.service.IDrainCorrelationService;
import com.yuzhi.master.drainRRmst.domain.vo.DrainRRmstVo;
import com.yuzhi.master.drainRRmst.service.IDrainRRmstService;
import com.yuzhi.master.drainRainfallData.domain.DrainStPptnRTj;
import com.yuzhi.master.drainRainfallData.domain.vo.DrainStPptnRTjVo;
import com.yuzhi.master.drainRainfallData.mapper.DrainStPptnRTjMapper;
import com.yuzhi.master.drainStPptnr.domain.bo.DrainStPptnRBo;
import com.yuzhi.master.drainStPptnr.domain.entity.DrainStPptnr;
import com.yuzhi.master.drainStPptnr.domain.request.DrainStPptnrReq;
import com.yuzhi.master.drainStPptnr.domain.vo.DrainStPptnrCharVo;
import com.yuzhi.master.drainStPptnr.domain.vo.DrainStPptnrVo;
import com.yuzhi.master.drainStPptnr.mapper.DrainStPptnrMapper;
import com.yuzhi.master.drainStPptnr.service.DrainStPptnrService;
import com.yuzhi.master.sewage.rmstSz.entity.request.DrainRmstSzReq;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class DrainStPptnrServiceImpl extends ServiceImpl<DrainStPptnrMapper, DrainStPptnr> implements DrainStPptnrService {

    // 实时降水量表-雨情(drain_st_pptn_r) - 一直插入数据
    private final DrainStPptnrMapper drainStPptnrMapper;

    // 降雨量统计表（日/小时）-雨情(drain_st_pptn_r_tj) - 统计数据
    private final DrainStPptnRTjMapper drainStPptnRTjMapper;

    @Autowired
    private IDrainCorrelationService iDrainCorrelationService;

    @Autowired
    private IDrainRRmstService iDrainRRmstService;

    @Override
    public DrainStPptnrVo getDrainStPptnr(String stcd) {
        // 查询当天最新一条数据
        return drainStPptnrMapper.selectCombinedData(stcd);
    }


    @Override
    public List<DrainStPptnrCharVo> getChartData(DrainStPptnrReq req) {
        return drainStPptnrMapper.selectChartData(
                req.getStcd(),
                req.getStartTime(),
                req.getEndTime()
        );
    }

    /**
     * 将Kafka监听到的消息进行存储保存
     * // 实时降水量表-雨情(drain_st_pptn_r) - 一直插入数据
     * private final DrainStPptnrMapper drainStPptnrMapper;
     * <p>
     * // 为实现-降雨量统计表（日/小时）-雨情(drain_st_pptn_r_tj) - 统计数据
     * private final DrainStPptnRTjMapper drainStPptnRTjMapper;
     *
     * @param msg Kafka收到的消息JSON字符串
     */
    @Override
    public void saveMessage(String msg) {
        try {

            JSONObject json = JSONObject.parseObject(msg);
            JSONObject payload = json.getJSONObject("payload");

            // 健壮性判断
            if (payload == null) {
                log.error("payload参数为空，暂不处理");
                return;
            }

            // 时间格式化器，匹配 "yyyy-MM-dd HH:mm:ss" 格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String deviceId = json.getString("deviceId");
            String timeStr = payload.getString("time");
            LocalDateTime tm = LocalDateTime.parse(timeStr, formatter);

            // ---------- 实时降水量表 DrainStPptnr  一直插入数据 -------------
            DrainStPptnr pptnr = new DrainStPptnr();
            // 设备id号
            pptnr.setStcd(deviceId);
            //  时间
            pptnr.setTm(tm);
            // 分钟降雨量
            pptnr.setDrp(parseBigDecimal(payload.getString("rain_min")));
            // 日降雨量
            pptnr.setDyp(parseBigDecimal(payload.getString("rain_day")));
            // 小时降雨量
            pptnr.setHrd(parseBigDecimal(payload.getString("rain_hour")));
            // 总降雨量
            pptnr.setRainTotal(parseBigDecimal(payload.getString("rain_total")));

            boolean flag = drainStPptnrMapper.insert(pptnr) > 0;
            if (flag) {
                //log.info("保存drain_st_pptn_r消息成功，deviceId={}, time={}", deviceId, tm);
            } else {
                log.error("保存drain_st_pptn_r消息失败，deviceId={}, time={}", deviceId, tm);
            }

        } catch (Exception e) {
            log.error("保存消息表失败", e);
        }
    }

    /**
     * 安全转换字符串为BigDecimal，异常时返回0
     */
    private BigDecimal parseBigDecimal(String str) {
        try {
            return (str == null || str.isEmpty()) ? BigDecimal.ZERO : new BigDecimal(str);
        } catch (NumberFormatException e) {
            log.warn("BigDecimal转换异常，值：{}", str, e);
            return BigDecimal.ZERO;
        }
    }

    /**
     * 监测预警展示数据
     *
     * @param bo
     */
    @Override
    public PageDataInfo<DrainStPptnrVo> monitorData(DrainStPptnRBo bo) {
        Page<DrainStPptnrVo> result = drainStPptnrMapper.monitorData(
                bo.getPageQuery().build(),
                buildQueryWrapper(bo)
        );
        return PageDataInfo.build(result);
    }


    /**
     * 构建查询条件
     *
     * @param request
     * @return
     */
    private Wrapper<DrainStPptnRBo> buildQueryWrapper(DrainStPptnRBo request) {
        QueryWrapper<DrainStPptnRBo> wrapper = Wrappers.query();
        wrapper.eq("dspr.deleted", Constants.UNDELETED);

        if (StringUtils.isNotBlank(request.getStcd())) {
            wrapper.eq("rmst.stcd", request.getStcd());
        }
        if (request.getStartTime() != null && request.getEndTime() != null) {
            wrapper.between("dspr.tm", request.getStartTime(), request.getEndTime());
        }
        return wrapper;
    }


    @Override
    public List<Map<String, Object>> getRainfallData(DrainRmstSzReq req) {
        //1,验证测站编码列表
        if (req.getRmstCodeList() == null || req.getRmstCodeList().isEmpty()) {
            throw new IllegalArgumentException("测站编码列表不能为空");
        }
        
        //2,获取查询类型
        Integer type = Integer.parseInt(req.getQueryType());
        
        //3,处理时间范围
        Date startTime = null;
        Date endTime = null;
        
        if (req.getCjTimeStrart() != null && req.getCjTimeEnd() != null) {
            // 如果前端传了时间参数，则使用前端的时间
            startTime = Date.from(req.getCjTimeStrart().atZone(ZoneId.systemDefault()).toInstant());
            endTime = Date.from(req.getCjTimeEnd().atZone(ZoneId.systemDefault()).toInstant());
            
            if (startTime.after(endTime)) {
                throw new IllegalArgumentException("开始时间不能晚于结束时间");
            }
        } else {
            // 如果前端没有传时间参数，则根据type自动设置时间范围
            endTime = new Date(); // 当前时间作为结束时间
            Calendar cal = Calendar.getInstance();
            cal.setTime(endTime);
            
            switch (type) {
                case 1: // 整点数据（最大1个月）
                    cal.add(Calendar.MONTH, -1);
                    startTime = cal.getTime();
                    break;
                case 2: // 每日最新数据（最大1周）
                    cal.add(Calendar.DAY_OF_MONTH, -7);
                    startTime = cal.getTime();
                    break;
                default:
                    throw new IllegalArgumentException("不支持的查询类型: " + type);
            }
        }
        
        //4,根据type进行时间范围约束（如果前端传了时间，需要检查是否超出限制）
        if (req.getCjTimeStrart() != null && req.getCjTimeEnd() != null) {
            Calendar cal = Calendar.getInstance();
            switch (type) {
                case 1: // 整点数据（最大1个月）
                    cal.setTime(endTime);
                    cal.add(Calendar.MONTH, -1);
                    if (startTime.before(cal.getTime())) {
                        startTime = cal.getTime();
                    }
                    break;
                case 2: // 每日最新数据（最大1周）
                    cal.setTime(endTime);
                    cal.add(Calendar.DAY_OF_MONTH, -7);
                    if (startTime.before(cal.getTime())) {
                        startTime = cal.getTime();
                    }
                    break;
            }
        }
        
        //5,查询多个测站的数据
        List<Map<String, Object>> allResults = new ArrayList<>();
        
        for (String stcd : req.getRmstCodeList()) {
            try {
                // 获取测站信息
                //DrainRRmstVo drainRRmstVo = iDrainRRmstService.selectDrainRRmstByStcd(stcd);
                DrainCorrelationVo drainCorrelationVo = iDrainCorrelationService.queryByStcd(stcd);
                if (drainCorrelationVo == null) {
                    log.warn("未找到测站编码为 {} 的雨量站信息", stcd);
                    continue;
                }
                DrainRRmstVo drainRRmstVo = iDrainRRmstService.selectDrainRRmstByStcd(drainCorrelationVo.getRainfallId());

                // 查询该测站的数据
                List<Map<String, Object>> stationData = drainStPptnrMapper.selectByFactAndType(
                        drainCorrelationVo.getRainfallId(), type, startTime, endTime);
                
                // 为每条数据添加测站信息标识
                for (Map<String, Object> data : stationData) {
                    data.put("originalStcd", stcd); // 原始请求的测站编码
                    data.put("rainfallStcd", drainCorrelationVo.getRainfallId()); // 实际查询的雨量站编码
                    data.put("stationName",drainRRmstVo.getStnm()); //雨量站名称ng
                }
                
                allResults.addAll(stationData);
                
            } catch (Exception e) {
                log.error("查询测站 {} 数据时发生错误: {}", stcd, e.getMessage(), e);
                // 继续查询其他测站，不中断整个查询过程
            }
        }
        
        //6,按时间排序
        allResults.sort((a, b) -> {
            Date timeA = (Date) a.get("tm");
            Date timeB = (Date) b.get("tm");
            if (timeA == null || timeB == null) {
                return 0;
            }
            return timeB.compareTo(timeA); // 降序排列，最新的在前
        });
        
        return allResults;
    }




    /**
     * 查询小时雨量
     *
     * @param bo 查询条件
     * @return 分页数据结果
     */
    @Override
    public PageDataInfo<DrainStPptnRTjVo> dailyRainfall(DrainStPptnRBo bo) {
        // 1. 处理分页参数，设置默认值
        PageQuery pageQuery = bo.getPageQuery() != null ? bo.getPageQuery() : new PageQuery();
        // 构建 MyBatis-Plus 的 Page 对象
        Page<DrainStPptnRTj> page = pageQuery.build();

        // 2. 构建查询条件
        LambdaQueryWrapper<DrainStPptnRTj> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DrainStPptnRTj::getDeleted, Constants.UNDELETED);

        // 时间范围条件
        if (bo.getStartTime() != null && bo.getEndTime() != null) {
            wrapper.between(DrainStPptnRTj::getTm, bo.getStartTime(), bo.getEndTime());
        } else if (bo.getStartTime() != null) {
            wrapper.ge(DrainStPptnRTj::getTm, bo.getStartTime());
        } else if (bo.getEndTime() != null) {
            wrapper.le(DrainStPptnRTj::getTm, bo.getEndTime());
        }

        // 测站编码过滤条件
        if (StringUtils.isNotBlank(bo.getStcd())) {
            wrapper.eq(DrainStPptnRTj::getStcd, bo.getStcd());
        }

        // 排序处理 - 优先使用分页参数中的排序，否则使用默认排序
        if (CollUtil.isEmpty(page.orders())) {
            wrapper.orderByAsc(DrainStPptnRTj::getTm);
        }

        // 3. 执行分页查询
        Page<DrainStPptnRTj> resultPage = drainStPptnRTjMapper.selectPage(page, wrapper);

        // 4. 转换为 VO 对象列表
        List<DrainStPptnRTjVo> records = resultPage.getRecords().stream()
                .map(this::convertToVo)  // 实体转 VO
                .collect(Collectors.toList());

        // 5. 处理空结果
        if (records.isEmpty()) {
            throw new BaseException("没有查询到指定时间段的数据");
        }

        // 6. 创建新的 Page 对象包装 VO 结果（修正核心点：直接设置 records，而非嵌套 List）
        Page<DrainStPptnRTjVo> voPage = new Page<>();
        voPage.setRecords(records); // 直接设置转换后的 VO 列表
        voPage.setTotal(resultPage.getTotal());
        voPage.setSize(resultPage.getSize());
        voPage.setCurrent(resultPage.getCurrent());
        voPage.setPages(resultPage.getPages());

        // 7. 利用 PageDataInfo 的 build 方法快速构建分页数据对象
        return PageDataInfo.build(voPage);
    }

    /**
     * 实体转 VO 的转换方法
     */
    private DrainStPptnRTjVo convertToVo(DrainStPptnRTj entity) {
        DrainStPptnRTjVo vo = new DrainStPptnRTjVo();
        // 属性复制，可根据实际需要调整（建议使用 MapStruct 替换 BeanUtils 以提升性能和类型安全）
        BeanUtils.copyProperties(entity, vo);
        // 如果有特殊转换需求，可以在这里处理
        return vo;
    }


    /**
     * 雨量分析统计
     * @param bo
     * @return
     */
    @Override
    public PageDataInfo<DrainStPptnrVo> getRainfallPageData(DrainStPptnRBo bo)
    {
        //查询类型(1:整点   2:实时)
        String queryType  =  bo.getQueryType();

        if("1".equals(queryType))  //雨量整点数据
        {
            Page<DrainStPptnrVo> result = drainStPptnrMapper.getStPptnrTjPageData(
                    bo.getPageQuery().build(),
                    buildQueryWrapper(bo)
            );
            return PageDataInfo.build(result);
        }
        else
        {
            // 雨量实时数据
            PageDataInfo<DrainStPptnrVo>   stPptnrPage  =   monitorData( bo);
            return stPptnrPage;
        }



    }

}
